#version 330 compatibility
precision highp float;

in vec3 Tangent;
in vec3 Binormal;

out vec3 v2f_WorldPos;
out vec3 v2f_ViewWS;
out vec3 v2f_Normal;
out vec2 v2f_TexCoord;
out vec3 v2f_LightTS;
out vec3 v2f_ViewTS;
out vec2 v2f_ParallaxOffset;

uniform mat4 ModelMatrix;                            // World matrix
uniform mat4 ViewProjectionMatrix;                   // VP matrix
uniform mat3 NormalMatrix;

uniform vec3 LightPosition;                 	// Light's position in world space
uniform vec3 CameraPosition;		// Camera's location
uniform vec2 BaseTextureRepeat;	// The tiling factor for base and normal map textures
uniform vec4 POMHeightMapScale;

void main()
{
    // Compute position in world space
    vec4 vPositionWS = ModelMatrix * gl_Vertex;
   gl_Position = ViewProjectionMatrix * vPositionWS;
    
    // Propagate texture coordinate through:
    v2f_TexCoord = gl_MultiTexCoord0.xy * BaseTextureRepeat.xy;

    // Transform normal, tangent and binormal vectors from object 
    // space to homogeneous projection space
    vec3 vNormalWS   = NormalMatrix * gl_Normal;
    vec3 vTangentWS  = NormalMatrix * Tangent;
    vec3 vBinormalWS = NormalMatrix * Binormal;
    
    // Output normal
    v2f_Normal = vNormalWS;
    
    // Calculate tangent basis
    mat3 WorldToTangent = mat3( vTangentWS, vBinormalWS, vNormalWS );
        
    // Compute denormalized light vector in world space
    vec3 vLightWS = LightPosition.xyz - vPositionWS.xyz;
    // Propagate the light vector (in tangent space)
    v2f_LightTS =  vLightWS * WorldToTangent;
    
    // Compute and output the world view vector (unnormalized)
    v2f_ViewWS = CameraPosition.xyz - vPositionWS.xyz;
    v2f_ViewTS  = v2f_ViewWS * WorldToTangent ;

    // Write world position
    v2f_WorldPos = vec3( vPositionWS.xyz );
    
    // Compute the ray direction for intersecting the 
    // height field profile with current view ray
         
    // Compute initial parallax displacement direction:
    vec2 vParallaxDirection = normalize(  v2f_ViewTS.xy );
       
    // The length of this vector determines the furthest amount of displacement:
    float fLength = length( v2f_ViewTS );
    float fParallaxLength = sqrt( fLength * fLength - v2f_ViewTS.z * v2f_ViewTS.z ) / v2f_ViewTS.z; 
       
    // Compute the actual reverse parallax displacement vector:
    v2f_ParallaxOffset = vParallaxDirection * fParallaxLength;
       
    // Need to scale the amount of displacement to account for different height ranges in height maps.
    v2f_ParallaxOffset *= POMHeightMapScale.x;
} 
